package club.emergency.wechat.redis.impl;

import club.emergency.wechat.exeception.redis.RedisException;
import club.emergency.wechat.redis.RedisOperation;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * Create with IntelliJ IDEA
 * Project Name: wechat
 * Package Name: club.emergency.wechat.redis.impl
 * Date: 2018/11/15
 *
 * @author: 快乐的小菌菌
 * Description:
 */
@Service
@Configuration
@PropertySource("classpath:/application.yml")
public class RedisOperationImpl<T> implements RedisOperation<T> {

    private StringRedisTemplate redisTemplate;

    public RedisOperationImpl(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Override
    public void add(String key, T value) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        if (value instanceof String) {
            valueOperations.set(key, value.toString());
        }
        try {
            valueOperations.set(key, new ObjectMapper().writeValueAsString(value));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void add(String key, T value, long time, TimeUnit timeUnit) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        if (value instanceof String) {
            valueOperations.set(key, value.toString());
        }
        try {
            valueOperations.set(key, new ObjectMapper().writeValueAsString(value), time, timeUnit);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void addExpire(String key, T value) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        if (value instanceof String) {
            valueOperations.set(key, value.toString(), 6, TimeUnit.HOURS);
        }
        try {
            valueOperations.set(key, new ObjectMapper().writeValueAsString(value), 6, TimeUnit.HOURS);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
    }

    @Override
    public T get(String key, Class<T> clazz) {
        Boolean flag = hasKey(key);
        if (Objects.isNull(flag) || !flag) {
            throw new RedisException("没有对应的key，请检查！");
        }
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        T t = null;
        try {
            t = new ObjectMapper().readValue(valueOperations.get(key), clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return t;
    }

    @Override
    public List<T> getList(String key, Class<T> clazz) {
        ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
        TypeFactory typeFactory = new ObjectMapper().getTypeFactory();
        CollectionLikeType collectionLikeType = typeFactory.constructCollectionLikeType(List.class, clazz);
        List<T> list = null;
        try {
            list = new ObjectMapper().readValue(valueOperations.get(key), collectionLikeType);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    @Override
    public Boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    @Override
    public void delete(String key) {
        redisTemplate.delete(key);
    }

    @Override
    public String keysConvert(String... strings) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < strings.length; i++) {
            if (i == strings.length - 1) {
                sb.append(strings[i]);
            } else {
                sb.append(strings[i]).append("_");
            }
        }
        return sb.toString();
    }

    @Override
    public List<String> getKeys(String key) {
        List<String> strings = null;
        Set<String> keys = redisTemplate.keys(key);
        if (Objects.nonNull(keys) && keys.size() != 0) {
            String[] keyArrayStr = new String[keys.size()];
            strings = Arrays.asList(keys.toArray(keyArrayStr));
        }
        return strings;
    }

    @Override
    public void zAdd(String key, String value, Double score) {
        ZSetOperations<String, String> stringStringZSetOperations = redisTemplate.opsForZSet();
        stringStringZSetOperations.add(key, value, score);
    }

    @Override
    public List<String> likeKeys(String key) {
        List<String> strings = null;
        Set<String> keys = redisTemplate.keys(key + "*");
        if (Objects.nonNull(keys)) {
            String[] keyArrayStr = new String[keys.size()];
            strings = Arrays.asList(keys.toArray(keyArrayStr));
        }
        return strings;
    }

    @Override
    public void deleteKeyList(List<String> keyList) {
        if (Objects.nonNull(keyList) && keyList.size() != 0) {
            keyList.forEach(this::delete);
        }
    }

}
